package terra.model.object.map;

import java.io.Serializable;

import terra.Config;
import terra.definitions.GroundDef;
import terra.managers.DefManager;
import terra.managers.MapManager;
import terra.model.map.Map;
import terra.model.object.GObject;
import terra.model.object.interfaces.SideInterface;
import terra.network.packet.server.TileInfo;

/**
 * Абстрактный класс, представляющий 1 блок игрового пространства. Содержит
 * основные параметры - координаты, ссылку на карту, в которой находится блок
 */
public abstract class AbstractMapObject extends GObject implements
		SideInterface, Serializable {

	private static final long serialVersionUID = 1L;

	public final static byte TYPE_GROUND = 1;
	public final static byte TYPE_WATER = 2;
	public final static byte TYPE_AIR = 0;

	// *Абсолютные координаты блока */
	private int x, y;
	// *Координаты блока относительно его карты */
	private short tileX, tileY;
	// *Ссылка на карту(чанк) */
	private transient Map map;
	// id типа блока
	protected short id = 0;

	public AbstractMapObject(int x, int y, short tX, short tY, Map map) {
		setX(x);
		setY(y);
		setTileX(tX);
		setTileY(tY);
		setMap(map);
	}

	public AbstractMapObject(AbstractMapObject other) {
		setX(other.getX());
		setY(other.getY());
		setTileX(other.getTileX());
		setTileY(other.getTileY());
		setMap(other.getMap());
	}

	public abstract boolean canMove();

	public abstract String getImage();

	public abstract String getBackgroundImage();

	public abstract byte getType();

	public abstract float getMass();
	
	public abstract void setMass(float mass);

	public abstract short getId();
	
	

	abstract void applyChange(AbstractMapObject mapObject);

	public Map getMap() {
		if (map == null)
			map = MapManager.getInstance().getMap(
					MapManager.getInstance().getMapIndex(
							getX() / Config.tileSize));
		return map;
	}

	public void setMap(Map map) {
		this.map = map;
	}

	public void setY(int y) {
		this.y = y;
	}

	public int getY() {
		return y;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getX() {
		return x;
	}

	public void setTileX(short tileX) {
		this.tileX = tileX;
	}

	public short getTileX() {
		return tileX;
	}

	public void setTileY(short tileY) {
		this.tileY = tileY;
	}

	public short getTileY() {
		return tileY;
	}

	public void setTileX(int tileX) {
		this.tileX = (short) tileX;
	}

	public void setTileY(int tileY) {
		this.tileY = (short) tileY;
	}

	/**
	 * Метод для получения соседнего тайла int position позиция соседнего тайла
	 * относительно данного
	 */
	public AbstractMapObject getNeighbor(int position) {
		if (getMap() == null)
			return null;
		if (position == DOWN) {
			if (getTileY() == Config.mapHeight - 1)
				return null;
			return getMap().getMap()[getTileX()][getTileY() + 1];
		} else if (position == LEFT) {
			if (getTileX() == 0) {
				if (MapManager.instance.getMaps().get(getMap().index - 1) == null)
					return null;
				return MapManager.instance.getMaps().get(getMap().index - 1)
						.getMap()[Config.mapWidth - 1][getTileY()];
			}
			return getMap().getMap()[getTileX() - 1][getTileY()];
		} else if (position == RIGHT) {
			if (getTileX() == Config.mapWidth - 1) {
				if (MapManager.instance.getMaps().get(getMap().index + 1) == null)
					return null;
				return MapManager.instance.getMaps().get(getMap().index + 1)
						.getMap()[0][getTileY()];
			}
			return getMap().getMap()[getTileX() + 1][getTileY()];
		} else if (position == UP) {
			if (getTileY() <= 0)
				return null;
			return getMap().getMap()[getTileX()][getTileY() - 1];
		}
		return null;
	}

	public static AbstractMapObject getNeighbor(int x, int y, int mapIndex,
			int position) {
		if (!MapManager.getInstance().getMaps().containsKey(mapIndex))
			return null;
		Map map = MapManager.getInstance().getMaps().get(mapIndex);
		if (position == DOWN) {
			if (y == Config.mapHeight - 1)
				return null;
			return map.getMap()[x][y + 1];
		} else if (position == LEFT) {
			if (x == 0) {
				if (MapManager.instance.getMaps().get(mapIndex - 1) == null)
					return null;
				return MapManager.instance.getMaps().get(mapIndex - 1).getMap()[Config.mapWidth - 1][y];
			}
			return map.getMap()[x - 1][y];
		} else if (position == RIGHT) {
			if (x == Config.mapWidth - 1) {
				if (MapManager.instance.getMaps().get(mapIndex + 1) == null)
					return null;
				return MapManager.instance.getMaps().get(mapIndex + 1).getMap()[0][y];
			}
			return map.getMap()[x + 1][y];
		} else if (position == UP) {
			if (y <= 0)
				return null;
			return map.getMap()[x][y - 1];
		}
		return null;
	}

	public static GroundDef getDef(short def) {
		return DefManager.groundDefs.get((int) def);
	}

	public void tileChanged() {
		if (MapManager.getInstance().init) {
			sendTileInfo();
		}
		for (int i = 0; i < 8; i++) {
			AbstractMapObject obj = getNeighbor(i);
			if (obj != null)
				obj.applyChange(this);
		}
		applyChange(this);
	}

	public abstract void sendTileInfo();

	public abstract TileInfo getTileInfo();

	public void setId(short id) {
		this.id = id;
	}
}
